package net.adetech.code.service.impl;

import com.alibaba.fastjson.JSONObject;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import net.adetech.code.DBEntity;
import net.adetech.code.service.IGenerateService;
import net.adetech.utils.UtilsCommon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by sunfeihu on 2017/4/17.
 */
@Service
public class GenerateServiceImpl implements IGenerateService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private Configuration configuration;


    @Override
    public void all(String[] tableNames) throws IOException, TemplateException {
        for (int i = 0; i < tableNames.length; i++) {
            this.entity(tableNames[i]);
            this.service(tableNames[i]);
            this.resetControl(tableNames[i]);
        }
    }


    /**
     * 根据数据库类型获取JAVA类型
     *
     * @param dbDataType 数据库数据类型
     * @return 转换后的JAVA数据类型
     */
    private String getJavaType(String dbDataType) {
        if ("text".equals(dbDataType) || "varchar".equals(dbDataType)) {
            return "String";
        }
        if ("int".equals(dbDataType)) {
            return "Integer";
        }
        if ("bigint".equals(dbDataType)) {
            return "Long";
        }
        if ("datetime".equals(dbDataType)) {
            return "java.util.Date";
        }
        if ("bit".equals(dbDataType)) {
            return "Boolean";
        }
        return "String";
    }

    /**
     * 获取JDBCTemplate数据转换格式
     *
     * @param dbDataType 数据库类型
     * @return JDBCTemplate数据格式
     */
    private String getMapperType(String dbDataType) {
        if ("text".equals(dbDataType) || "varchar".equals(dbDataType)) {
            return "String";
        }
        if ("int".equals(dbDataType)) {
            return "Int";
        }
        if ("bigint".equals(dbDataType)) {
            return "Long";
        }
        if ("datetime".equals(dbDataType)) {
            return "Date";
        }
        if ("bit".equals(dbDataType)) {
            return "Boolean";
        }
        return "String";
    }


    private DBEntity initDBEntity(String tableName) {
        DBEntity dbEntity = new DBEntity();
        String dbName = "dcweb";
        dbEntity.setCamelCaseName(UtilsCommon.camelName(tableName));
        dbEntity.setTableName(tableName);
        dbEntity.setHungarianNotationName(tableName);
        String pascalName = dbEntity.getCamelCaseName();
        pascalName = pascalName.substring(0, 1).toUpperCase() + pascalName.substring(1);
        dbEntity.setPascalName(pascalName);
        dbEntity.setFodlerName("/" + tableName.replaceAll("_", "/"));
        String packageName = tableName;
        packageName = packageName.substring(0, packageName.indexOf("_"));
        dbEntity.setPackageName(packageName);

        String SYSTEM = "";
        String MODULE = "";

        if (tableName.indexOf("_") != -1) {
            SYSTEM = tableName.substring(0, tableName.indexOf("_"));
        }
        MODULE = tableName.substring(tableName.indexOf("_") + 1);

        JSONObject hungarianNotationFields = new JSONObject();
        JSONObject camelCaseFields = new JSONObject();
        JSONObject pascalFields = new JSONObject();

        JSONObject obj1 = null;

        List<JSONObject> fieldsNoId = new ArrayList<JSONObject>(0);

        List<JSONObject> fieldsNoDefault = new ArrayList<JSONObject>(0);

        final String sql = "SELECT COLUMN_NAME , DATA_TYPE , COLUMN_COMMENT FROM information_schema. COLUMNS WHERE table_name = ?AND table_schema = ?";
        List<Map<String, Object>> list = jdbcTemplate.queryForList(sql, new Object[]{tableName, dbName});
        String insertField = "";
        String insertQField = "";
        String updateField = "";
        if (null != list) {
            String COLUMN_NAME = "";
            String DATA_TYPE = "";
            String COLUMN_COMMENT = "";

            Boolean haveId = false;
            for (Map<String, Object> m : list) {
                COLUMN_NAME = UtilsCommon.getString(m.get("COLUMN_NAME"));
                DATA_TYPE = UtilsCommon.getString(m.get("DATA_TYPE"));
                COLUMN_COMMENT = UtilsCommon.getString(m.get("COLUMN_COMMENT"));
                COLUMN_COMMENT = COLUMN_COMMENT.replaceAll("\r\n", "").replaceAll("\r", "").replaceAll("\n", "");
                if (!"id".equals(COLUMN_NAME) && !"uuid".equals(COLUMN_NAME) && !"add_date".equals(COLUMN_NAME) && !"add_ip".equals(COLUMN_NAME) && !"add_user".equals(COLUMN_NAME) && !"update_date".equals(COLUMN_NAME) && !"update_ip".equals(COLUMN_NAME) && !"update_user".equals(COLUMN_NAME) && !"is_delete".equals(COLUMN_NAME)) {
                    updateField += COLUMN_NAME + "=?,";
                }

                obj1 = new JSONObject();
                obj1.put("COLUMN_NAME", COLUMN_NAME);
                obj1.put("DATA_TYPE", DATA_TYPE);
                obj1.put("JAVA_TYPE", this.getJavaType(DATA_TYPE));
                obj1.put("MAPPER_TYPE", this.getMapperType(DATA_TYPE));
                obj1.put("COLUMN_COMMENT", COLUMN_COMMENT);
                hungarianNotationFields.put(COLUMN_NAME, obj1);

                obj1 = new JSONObject();
                obj1.put("COLUMN_NAME", UtilsCommon.camelName(COLUMN_NAME));
                obj1.put("DATA_TYPE", DATA_TYPE);
                obj1.put("JAVA_TYPE", this.getJavaType(DATA_TYPE));
                obj1.put("MAPPER_TYPE", this.getMapperType(DATA_TYPE));
                obj1.put("COLUMN_COMMENT", COLUMN_COMMENT);
                camelCaseFields.put(COLUMN_NAME, obj1);

                obj1 = new JSONObject();
                pascalName = UtilsCommon.camelName(COLUMN_NAME);
                pascalName = pascalName.substring(0, 1).toUpperCase() + pascalName.substring(1);
                obj1.put("COLUMN_NAME", pascalName);
                obj1.put("DATA_TYPE", DATA_TYPE);
                obj1.put("JAVA_TYPE", this.getJavaType(DATA_TYPE));
                obj1.put("MAPPER_TYPE", this.getMapperType(DATA_TYPE));
                obj1.put("COLUMN_COMMENT", COLUMN_COMMENT);
                pascalFields.put(COLUMN_NAME, obj1);

                if (!"id".equals(COLUMN_NAME) && !"uuid".equals(COLUMN_NAME) && !"add_date".equals(COLUMN_NAME) && !"add_ip".equals(COLUMN_NAME) && !"add_user".equals(COLUMN_NAME) && !"update_date".equals(COLUMN_NAME) && !"update_ip".equals(COLUMN_NAME) && !"update_user".equals(COLUMN_NAME) && !"is_delete".equals(COLUMN_NAME)) {
                    fieldsNoDefault.add(obj1);
                }

                if (!"id".equals(COLUMN_NAME)) {
                    insertField += COLUMN_NAME + ",";
                    insertQField += "?,";
                    fieldsNoId.add(obj1);
                }

                if (COLUMN_NAME.equals("id")) {
                    haveId = true;
                }

            }
            if (!haveId) {
                return null;
            }
            dbEntity.setFieldsNoId(fieldsNoId);
            dbEntity.setFieldsNoDefault(fieldsNoDefault);
            if (insertField.length() > 0) {
                insertField = insertField.substring(0, insertField.length() - 1);
            }
            if (insertQField.length() > 0) {
                insertQField = insertQField.substring(0, insertQField.length() - 1);
            }
            if (updateField.length() > 0) {
                updateField = updateField.substring(0, updateField.length() - 1);
            }
            dbEntity.setInsertField(insertField);
            dbEntity.setInsertQField(insertQField);
            dbEntity.setUpdateField(updateField);
        }
        dbEntity.setSystem(SYSTEM);
        dbEntity.setModule(MODULE);
        dbEntity.setHungarianNotationFields(hungarianNotationFields);
        dbEntity.setCamelCaseFields(camelCaseFields);
        dbEntity.setPascalFields(pascalFields);
        return dbEntity;
    }

    @Override
    public void service(String tableName) throws IOException, TemplateException {
        String fodler = tableName.replaceAll("_", "/");
        fodler = fodler.substring(0, fodler.indexOf("/"));
        fodler = "/" + fodler;
        DBEntity dbEntity = this.initDBEntity(tableName);
        if (null == dbEntity) {
            return;
        }
        Template t = configuration.getTemplate("IService.ftl");
        //获取输出路径
        String outFile = this.getClass().getClassLoader().getResource("").getFile();
        outFile = outFile + File.separator + "output" + File.separator + fodler + File.separator + "service";
        File outFolder = new File(outFile);
        if (!outFolder.exists()) {
            outFolder.mkdirs();
        }
        outFile = outFile + File.separator + "I" + dbEntity.getPascalName() + "Service.java";
        Map root = new HashMap();
        root.put("DBEntity", dbEntity);
        FileOutputStream fos = new FileOutputStream(outFile);
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        BufferedWriter bw = new BufferedWriter(osw, 1024);
        t.process(root, bw);

        t = configuration.getTemplate("ServiceImpl.ftl");
        outFile = this.getClass().getClassLoader().getResource("").getFile();
        outFile = outFile + File.separator + "output" + File.separator + fodler + File.separator + "service" + File.separator + "impl";
        outFolder = new File(outFile);
        if (!outFolder.exists()) {
            outFolder.mkdirs();
        }
        outFile = outFile + File.separator + dbEntity.getPascalName() + "ServiceImpl.java";
        root = new HashMap();
        root.put("DBEntity", dbEntity);
        fos = new FileOutputStream(outFile);
        osw = new OutputStreamWriter(fos, "UTF-8");
        bw = new BufferedWriter(osw, 1024);
        t.process(root, bw);
    }

    @Override
    public void control(String tableName) throws IOException, TemplateException {
        String fodler = tableName.replaceAll("_", "/");
        fodler = fodler.substring(0, fodler.indexOf("/"));
        fodler = "/" + fodler;
        DBEntity dbEntity = this.initDBEntity(tableName);
        if (null == dbEntity) {
            return;
        }
        Template t = configuration.getTemplate("Control.ftl");
        //获取输出路径
        String outFile = this.getClass().getClassLoader().getResource("").getFile();
        outFile = outFile + File.separator + "output" + File.separator + fodler + File.separator + "controller";
        File outFolder = new File(outFile);
        if (!outFolder.exists()) {
            outFolder.mkdirs();
        }
        outFile = outFile + File.separator + dbEntity.getPascalName() + "Controller.java";
        Map root = new HashMap();
        root.put("DBEntity", dbEntity);
        FileOutputStream fos = new FileOutputStream(outFile);
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        BufferedWriter bw = new BufferedWriter(osw, 1024);
        t.process(root, bw);
    }

    @Override
    public void resetControl(String tableName) throws IOException, TemplateException {
        String fodler = tableName.replaceAll("_", "/");
        fodler = fodler.substring(0, fodler.indexOf("/"));
        fodler = "/" + fodler;
        DBEntity dbEntity = this.initDBEntity(tableName);
        if (null == dbEntity) {
            return;
        }
        Template t = configuration.getTemplate("RestControl.ftl");
        //获取输出路径
        String outFile = this.getClass().getClassLoader().getResource("").getFile();
        outFile = outFile + File.separator + "output" + File.separator + fodler + File.separator + "rest";
        File outFolder = new File(outFile);
        if (!outFolder.exists()) {
            outFolder.mkdirs();
        }
        outFile = outFile + File.separator + dbEntity.getPascalName() + "RestController.java";
        Map root = new HashMap();
        root.put("DBEntity", dbEntity);
        FileOutputStream fos = new FileOutputStream(outFile);
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        BufferedWriter bw = new BufferedWriter(osw, 1024);
        t.process(root, bw);
    }

    @Override
    public void entity(String tableName) throws IOException, TemplateException {
        String fodler = tableName.replaceAll("_", "/");
        fodler = fodler.substring(0, fodler.indexOf("/"));
        fodler = "/" + fodler;
        DBEntity dbEntity = this.initDBEntity(tableName);
        if (null == dbEntity) {
            return;
        }
        Template t = configuration.getTemplate("Entity.ftl");
        //获取输出路径
        String outFile = this.getClass().getClassLoader().getResource("").getFile();
        outFile = outFile + File.separator + "output" + File.separator + fodler + File.separator + "entity";
        File outFolder = new File(outFile);
        if (!outFolder.exists()) {
            outFolder.mkdirs();
        }
        outFile = outFile + File.separator + dbEntity.getPascalName() + ".java";
        Map root = new HashMap();
        root.put("DBEntity", dbEntity);
        FileOutputStream fos = new FileOutputStream(outFile);
        OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF-8");
        BufferedWriter bw = new BufferedWriter(osw, 1024);
        t.process(root, bw);
    }
}
